package com.topscomm.mis.cbb.file.compare.word.util;

import com.alibaba.fastjson.JSON;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.mis.cbb.file.compare.cj.CjSystemConst;
import com.topscomm.mis.cbb.file.compare.word.service.PoiCommentService;
import com.topscomm.pub.vo.ResponseResult;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import static com.topscomm.mis.cbb.file.compare.cj.CjSystemConst.SectionFlag;

/**
 * @description:
 * @author: zhanglongfei
 * @date: 2023/2/21 18:49
 */
public class PoiWordUtil {

    /**
     * @param document:
     * @param insertBeforParagraph:
     * @param sourceTable:
     * @description: 在指定段落前复制插入一个表格
     * @return: int
     * @author: zhanglongfei
     * @date: 2023/2/22 14:06
     * @modify:
     */
    public static int insertCopyTable(XWPFDocument document, XWPFParagraph insertBeforParagraph,
        XWPFTable sourceTable) {
        XWPFTable newTable;
        if (insertBeforParagraph != null) {
            XmlCursor cursor = insertBeforParagraph.getCTP().newCursor();
            newTable = document.insertNewTbl(cursor);
        } else {
            newTable = document.createTable();
        }
        int tablePos = getTablePos(document, newTable);
        document.setTable(tablePos, sourceTable);
        return tablePos;
    }

    /**
     * @param document:
     * @param insertBeforTable:
     * @param sourceParagraph:
     * @description: 在指定位置表格前插入段落
     * @return: int
     * @author: zhanglongfei
     * @date: 2023/2/22 14:09
     * @modify:
     */
    public static int insertCopyParagraph(XWPFDocument document, XWPFTable insertBeforTable,
        XWPFParagraph sourceParagraph) {
        XWPFParagraph newParagraph;
        if (insertBeforTable != null) {
            XmlCursor cursor = insertBeforTable.getCTTbl().newCursor();
            newParagraph = document.insertNewParagraph(cursor);
        } else {
            newParagraph = document.createParagraph();
        }

        int paragraphPos = getParagraphPos(document, newParagraph);
        // document.setParagraph(sourceParagraph, paragraphPos);
        // newParagraph.createRun().setText(sourceParagraph.getText());

        XWPFRun newRun = newParagraph.createRun();
        newParagraph.setAlignment(sourceParagraph.getAlignment());
        newParagraph.setFirstLineIndent(sourceParagraph.getFirstLineIndent());
        newParagraph.setPageBreak(sourceParagraph.isPageBreak());
        newParagraph.setSpacingBetween(sourceParagraph.getSpacingBetween());
        if (sourceParagraph.getRuns().size() > 0) {
            XWPFRun copyRun = sourceParagraph.getRuns().get(0);
            newRun.setText(sourceParagraph.getText());
            newRun.setBold(copyRun.isBold());
            newRun.setFontFamily(copyRun.getFontFamily());
            if (copyRun.getFontSizeAsDouble() != null) {
                newRun.setFontSize(copyRun.getFontSizeAsDouble());
            }

        }

        return paragraphPos;
    }

    /**
     * @param cell:
     * @param sourceParagraph:
     * @description: 在指定位置表格前插入段落
     * @return: int
     * @author: zhanglongfei
     * @date: 2023/2/22 14:09
     * @modify:
     */
    public static int insertCopyParagraph(XWPFTableCell cell, XWPFParagraph sourceParagraph) {
        XWPFParagraph newParagraph = cell.addParagraph();
        if (sourceParagraph != null) {
            XWPFRun newRun = newParagraph.createRun();
            newRun.setText(sourceParagraph.getText());
        }
        return cell.getParagraphs().size() - 1;
    }

    /**
     * @param document:
     * @param table:
     * @description: 获取表格序号
     * @return: int
     * @author: zhanglongfei
     * @date: 2023/2/22 14:38
     * @modify:
     */
    public static int getTablePos(XWPFDocument document, XWPFTable table) {
        if (table == null) {
            return document.getTables().size();
        }
        int elementPos = document.getPosOfTable(table);
        return document.getTablePos(elementPos);
    }

    /**
     * @param document:
     * @param paragraph:
     * @description: 获取表格序号
     * @return: int
     * @author: zhanglongfei
     * @date: 2023/2/22 14:38
     * @modify:
     */
    public static int getParagraphPos(XWPFDocument document, XWPFParagraph paragraph) {
        if (paragraph == null) {
            return document.getParagraphs().size();
        }
        int elementPos = document.getPosOfParagraph(paragraph);
        return document.getParagraphPos(elementPos);
    }

    /**
     * @param cell:
     * @param paragraph:
     * @description: 获取表格序号
     * @return: int
     * @author: zhanglongfei
     * @date: 2023/2/22 14:38
     * @modify:
     */
    public static int getParagraphPos(XWPFTableCell cell, XWPFParagraph paragraph) {
        if (paragraph == null) {
            return cell.getParagraphs().size();
        }
        int i = 0;
        for (XWPFParagraph item : cell.getParagraphs()) {
            if (item.equals(paragraph)) {
                return i;
            }
            i++;
        }
        return cell.getParagraphs().size();
    }

    /**
     * @param element:
     * @param color:
     * @description: 设置颜色
     * @return: void
     * @author: zhanglongfei
     * @date: 2023/2/23 19:09
     * @modify:
     */
    public static void assignColor(XWPFRun element, String color) {
        if (element == null) {
            return;
        }
        CTShd cTShd = element.getCTR().addNewRPr().addNewShd();
        cTShd.setVal(STShd.CLEAR);
        cTShd.setFill(color);
    }

    /**
     * @param element:
     * @param color:
     * @description: 设置颜色
     * @return: void
     * @author: zhanglongfei
     * @date: 2023/2/23 19:09
     * @modify:
     */
    public static void assignColor(XWPFParagraph element, String color) {
        if (element == null) {
            return;
        }
        for (XWPFRun run : element.getRuns()) {
            assignColor(run, color);
        }
    }

    /**
     * @param element:
     * @param color:
     * @description: 设置颜色
     * @return: void
     * @author: zhanglongfei
     * @date: 2023/2/23 19:09
     * @modify:
     */
    public static void assignColor(XWPFTableCell element, String color) {
        if (element == null) {
            return;
        }
        element.setColor(color);
    }

    /**
     * @param element:
     * @param color:
     * @description: 设置颜色
     * @return: void
     * @author: zhanglongfei
     * @date: 2023/2/23 19:09
     * @modify:
     */
    public static void assignColor(XWPFTableRow element, String color) {
        if (element == null) {
            return;
        }
        for (XWPFTableCell cell : element.getTableCells()) {
            cell.setColor(color);
        }
    }

    /**
     * @param element:
     * @param color:
     * @description: 设置颜色
     * @return: void
     * @author: zhanglongfei
     * @date: 2023/2/23 19:09
     * @modify:
     */
    public static void assignColor(XWPFTable element, String color) {
        if (element == null) {
            return;
        }
        for (XWPFTableRow row : element.getRows()) {
            assignColor(row, color);
        }
    }

    /**
     * @param document:
     * @param text:
     * @description: 添加新页，并在新页第一行添加批注
     * @return: void
     * @author: zhanglongfei
     * @date: 2023/2/21 15:49
     * @modify:
     */
    public static void addPage(XWPFDocument document, String text) {
        XWPFParagraph newParagraph = addPage(document);
        XWPFRun newRun = newParagraph.createRun();
        newRun.setText(text);
        CTShd cTShd = newRun.getCTR().addNewRPr().addNewShd();
        cTShd.setVal(STShd.CLEAR);
        cTShd.setFill(CjSystemConst.CjCompareJobResultColor.Del);
    }

    /**
     * @param document:
     * @description: 添加新页
     * @return: org.apache.poi.xwpf.usermodel.XWPFParagraph
     * @author: zhanglongfei
     * @date: 2023/2/21 15:49
     * @modify:
     */
    public static XWPFParagraph addPage(XWPFDocument document) {
        XWPFParagraph newParagraph = document.createParagraph();
        newParagraph.createRun().addBreak(BreakType.PAGE);
        return newParagraph;
    }


    /**
     * description 文档合并
     *
     * @param files
     * @return void
     * @author wxm
     * @date 2023-06-17 08:33:42
     * @modify
     */
    public static byte[] mergeDocuments(MultipartFile[] files, boolean useSection) throws Exception {

        List<File> mergeFileList = new ArrayList<>();
        ByteArrayOutputStream out = null;
        XWPFDocument doc = null;
        List<XWPFDocument> documentList = null;
        byte[] result = null;
        try {
            if (files == null) {
                throw new ServiceException("文件不能为空");
            }
            for (MultipartFile file : files) {
                File attachFile = CbbFileUtil.multipartFileToFile(file);
                mergeFileList.add(attachFile);
            }
            documentList = new ArrayList<>();
            for (File file : mergeFileList) {
                try (FileInputStream in = new FileInputStream(
                    file.getPath())) {
                    OPCPackage open = OPCPackage.open(in);
                    XWPFDocument document = new XWPFDocument(open);
                    documentList.add(document);
                }
            }
            // 遍历拼接
            doc = documentList.get(0);
            for (int i = 0; i < documentList.size(); i++) {
                if(useSection){
                    documentList.get(i).createParagraph().createRun().setText(SectionFlag);
                }
                if (i != 0) {
                    if (i < documentList.size() - 1) {
                        XWPFParagraph paragraph = documentList.get(i+1).getParagraphs().get(0);
                        paragraph.insertNewRun(0).addBreak(BreakType.PAGE);
                    }
                    appendBody(doc, documentList.get(i));
                }
            }
            // 转为流
            out = new ByteArrayOutputStream();
            if (doc != null) {
                doc.write(out);
            }
//            CbbFileUtil.bytesToFile(out.toByteArray(),"D:/aa/","test.docx");
        } catch (Exception e) {
            throw new ServiceException(e);
        } finally {
            // 关闭流
            if (out != null) {
                out.close();
            }
            if (doc != null) {
                doc.close();
            }
            if (!CollectionUtils.isEmpty(documentList)){
                for (XWPFDocument xwpfDocument : documentList) {
                    if (xwpfDocument != null) {
                        xwpfDocument.close();
                    }
                }
            }
            // 清理生成的文件
            for (File file : mergeFileList) {
                if (file != null) {
                    file.delete();
                }
            }
        }
        result = out.toByteArray();
        return result;
    }


    /**
     * description 文档拼接-处理图片
     *
     * @param src
     * @param append
     * @return void
     * @author wxm
     * @date 2023-06-17 08:24:56
     * @modify
     */
    private static void appendBody(XWPFDocument src, XWPFDocument append) throws Exception {
        // 在第一个段落中插入换行符
//        XWPFParagraph paragraph = append.getParagraphs().get(0);
//        paragraph.insertNewRun(0).addBreak(BreakType.PAGE);
        CTBody src1Body = src.getDocument().getBody();
        CTBody src2Body = append.getDocument().getBody();

        List<XWPFPictureData> allPictures = append.getAllPictures();
        // 记录图片合并前及合并后的ID
        Map<String, String> map = new HashMap<>();
        for (XWPFPictureData picture : allPictures) {
            String before = append.getRelationId(picture);
            //将原文档中的图片加入到目标文档中
            String after = src.addPictureData(picture.getData(), Document.PICTURE_TYPE_PNG);
            map.put(before, after);
        }

        appendBody(src1Body, src2Body, map);

    }

    /**
     * description 文档拼接
     *
     * @param src
     * @param append
     * @param map
     * @return void
     * @author wxm
     * @date 2023-06-17 08:25:10
     * @modify
     */
    private static void appendBody(CTBody src, CTBody append, Map<String, String> map)
        throws Exception {
        XmlOptions optionsOuter = new XmlOptions();
        optionsOuter.setSaveOuter();
        String appendString = append.xmlText(optionsOuter);

        String srcString = src.xmlText();
        String prefix = srcString.substring(0, srcString.indexOf(">") + 1);
        String mainPart = srcString
            .substring(srcString.indexOf(">") + 1, srcString.lastIndexOf("<"));
        String suffix = srcString.substring(srcString.lastIndexOf("<"));
        String addPart = appendString
            .substring(appendString.indexOf(">") + 1, appendString.lastIndexOf("<"));

        if (map != null && !map.isEmpty()) {
            //对xml字符串中图片ID进行替换
            for (Map.Entry<String, String> set : map.entrySet()) {
                addPart = addPart.replace(set.getKey(), set.getValue());
            }
        }
        //将两个文档的xml内容进行拼接
        CTBody makeBody = CTBody.Factory.parse(prefix + mainPart + addPart + suffix);

        src.set(makeBody);
    }

}
